package com.test;

import java.util.*;
import java.io.Writer;
import java.io.IOException;
import java.text.DecimalFormat;

/**
 * Created by IntelliJ IDEA.
 * User: adenysenko
 * Date: Oct 3, 2005
 * Time: 4:01:23 PM
 */
public class FrameStats {
    Map<String,FrameStats> allNested = new HashMap<String,FrameStats>();

    int depth=1;
    int count=0;
    String location="";

    public FrameStats recordNestedInvocation(String location){
        return recordNestedInvocation(location, 1);
    }
    private FrameStats recordNestedInvocation(String location, int increment){
        FrameStats nested = allNested.get(location);
        if( nested==null ){
            nested = new FrameStats();
            nested.location=location;
            nested.depth=this.depth+1;
            allNested.put(location, nested);
        }
        nested.count += increment;
        return nested;
    }
    public void print(Writer w) throws IOException {
        print(w,0);
    }
    private void print(Writer w, int nestLevel) throws IOException {
        List<FrameStats> l = sortNested();
        for( FrameStats fs : l ){
            println(w, nestLevel, fs.count + "  "+fs.location);
            fs.print(w,nestLevel + 1);
        }
    }

    void saveXML(Writer w, String filterBranch) throws IOException {
        FrameStats groupByMethods = new FrameStats();
        w.write("\r\n<root>");

        int[] maxHolder = new int[]{0};
        w.write("\r\n<tree>");
        execSaveXML(w, filterBranch, groupByMethods, maxHolder, new ArrayList<String>());
        w.write("\r\n</tree>");

        w.write("\r\n<methods>");
        List<FrameStats> l = groupByMethods.sortNested();
        for( FrameStats fs : l ){
          writeStats(w, fs, maxHolder[0]);
        }
        w.write("\r\n</methods>");

        w.write("\r\n</root>");
    }

    private void execSaveXML(Writer w, String filterBranch, FrameStats groupByMethods,
                             int[] maxHolder, List<String> stackLocations)
            throws IOException {
        List<FrameStats> l = sortNested();
        for( FrameStats fs : l ){
            String filter = filterBranch;
            if( filter!=null ){
              if( fs.location.contains(filter) ){
                  filter=null;
                  maxHolder[0] = fs.count;
              }
            }
            if( filter==null ){
              if( !stackLocations.contains(fs.location) ){
                groupByMethods.recordNestedInvocation(fs.location, fs.count);
              }
              writeStats(w, fs, maxHolder[0]);
            }
            stackLocations.add(fs.location);
            fs.execSaveXML(w,filter, groupByMethods, maxHolder, stackLocations);
            stackLocations.remove(stackLocations.size()-1);
            if( filter==null && !fs.allNested.isEmpty() ){
              w.write("</loc>");
            }
        }
    }

    private void writeStats(Writer w, FrameStats fs, double max) throws IOException {
        DecimalFormat df = new DecimalFormat();
        df.setMaximumFractionDigits(1);
        double perc = fs.count/max*100;

        w.write("\r\n");
        for( int i=0; i<depth; i++ ){
            w.write(' ');
        }
        w.write("<loc l='"+ df.format(perc) + "%  "+
                fs.location.replaceAll("<init>","&lt;init&gt;")
                + "'");
        if( fs.allNested.isEmpty() ){
            w.write("/>");
        }else{
            w.write(">");
        }
    }

    private List<FrameStats> sortNested() {
        List<FrameStats> l = new ArrayList<FrameStats>(allNested.values());
        Collections.sort(l, new Comparator(){
            public int compare(Object o1, Object o2) {
                long l1=((FrameStats)o1).count;
                long l2=((FrameStats)o2).count;
                return new Long(l2).compareTo(new Long(l1)); // reverse order
            }
        });
        return l;
    }

    private void println(Writer w, int nestLevel, String text) throws IOException{
        for( int i=0; i<nestLevel*2; i++){
            w.write(' ');
        }
        w.write(text+"\n");
    }
}
